package cn.zhejianglao.shirotemplate.exception;

import cn.zhejianglao.shirotemplate.common.model.Response;
import com.fasterxml.jackson.databind.JsonMappingException;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.ShiroException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;


/**
 * global exception handler
 */

@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * business exception handler
     *
     * @param exception business exception
     * @return response
     */
    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public Response<String> businessExceptionHandler(BusinessException exception) {
        log.warn("business exception: {}", exception.getMessage());
        return Response.exceptionResponse(exception);
    }

    /**
     * Shiro exceptions
     *
     * @param e Shiro exceptions
     * @return response
     */
    @ExceptionHandler(ShiroException.class)
    @ResponseBody
    public Response<String> doHandleShiroException(ShiroException e) {
        Response<String> response = new Response<>();
        response.setCode(ExceptionCode.Permission.AUTHORIZATION_PARAM_CODE);
        if (e instanceof IncorrectCredentialsException) {
            response.setMessage("Invalid Password");
        } else if (e instanceof UnknownAccountException) {
            response.setMessage("Non-existing account");
        } else if (e instanceof LockedAccountException) {
            response.setMessage("Account locked");
        } else if (e instanceof UnauthorizedException) {
            response.setMessage("Insufficient permission");
        }
        return response;
    }

    /**
     * system exception
     *
     * @param exception exception
     * @return response
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Response<String> exceptionHandler(Exception exception) {
        log.error("system exception", exception);
        if (exception.getCause() instanceof HttpRequestMethodNotSupportedException) {
            return new Response<>(
                    ExceptionCode.System.INTERFACE_NOT_EXIST_OR_REQUEST_MODE_ERROR_CODE,
                    ExceptionCode.System.INTERFACE_NOT_EXIST_OR_REQUEST_MODE_ERROR_MSG
            );
        } else {
            return new Response<>(
                    ExceptionCode.System.SYSTEM_ERROR_CODE,
                    ExceptionCode.System.SYSTEM_ERROR_MSG + "->" + exception
            );
        }
    }

    /**
     * system runtime exception handler
     *
     * @param exception exception
     * @return response
     */
    @ExceptionHandler(value = RuntimeException.class)
    @ResponseBody
    public Response<String> runtimeExceptionHandler(RuntimeException exception) {
        log.error("system runtime exception", exception);
        if (exception.getCause() instanceof JsonMappingException) {
            return new Response<>(
                    ExceptionCode.System.CONVERT_ERROR_CODE,
                    ExceptionCode.System.CONVERT_ERROR_MSG
            );
        } else {
            return new Response<>(
                    ExceptionCode.System.SYSTEM_ERROR_CODE,
                    ExceptionCode.System.SYSTEM_ERROR_CODE + "->" + exception
            );
        }
    }
}
